import {
  MonacoEditorLanguageClientWrapper,
  UserConfig,
} from "monaco-editor-wrapper/bundle";
import { buildWorkerDefinition } from "monaco-editor-workers";
import { addMonacoStyles } from "monaco-editor-wrapper/styles";

/**
 * Setup Monaco's own workers and also incorporate the necessary styles for the monaco-editor
 */
function setup() {
  buildWorkerDefinition(
    "./monaco-editor-workers/workers",
    new URL("", window.location.href).href,
    false
  );
  addMonacoStyles("monaco-editor-styles");
}

function getMonarchGrammar() {
  return {
    keywords: [
      "break",
      "const",
      "continue",
      "else",
      "float",
      "if",
      "int",
      "person",
      "return",
      "void",
      "while",
    ],
    operators: [
      "!",
      "!=",
      "%",
      "&&",
      "*",
      "+",
      ",",
      "-",
      "/",
      ";",
      "<",
      "<=",
      "=",
      "==",
      ">",
      ">=",
      "||",
    ],
    symbols: /!|!=|%|&&|\(|\)|\*|\+|,|-|\/|;|<|<=|=|==|>|>=|\[|\]|\{|\|\||\}/,

    tokenizer: {
      initial: [
        { regex: /[0-9]+/, action: { token: "number" } },
        { regex: /[0-9]+\.[0-9]*/, action: { token: "number" } },
        { regex: /\.[0-9]*/, action: { token: "number" } },
        {
          regex: /int|float/,
          action: {
            cases: {
              "@keywords": { token: "keyword" },
              "@default": { token: "BType" },
            },
          },
        },
        {
          regex: /void|int|float/,
          action: {
            cases: {
              "@keywords": { token: "keyword" },
              "@default": { token: "FuncType" },
            },
          },
        },
        {
          regex: /[a-zA-Z0-9]+/,
          action: {
            cases: {
              "@keywords": { token: "keyword" },
              "@default": { token: "Ident" },
            },
          },
        },
        { include: "@whitespace" },
        {
          regex: /@symbols/,
          action: {
            cases: {
              "@operators": { token: "operator" },
              "@default": { token: "" },
            },
          },
        },
      ],
      whitespace: [
        { regex: /\s+/, action: { token: "white" } },
        { regex: /\/\*/, action: { token: "comment", next: "@comment" } },
        { regex: /\/\/[^\n\r]*/, action: { token: "comment" } },
      ],
      comment: [
        { regex: /[^/\*]+/, action: { token: "comment" } },
        { regex: /\*\//, action: { token: "comment", next: "@pop" } },
        { regex: /[/\*]/, action: { token: "comment" } },
      ],
    },
  };
}

function getMainCode() {
  let mainCode = `
  void main(){
    int a,b;
    a = 0x1;
    b = 7;
    int c[10];
    float d = 2.2345;
    string e = "hello world";
    a=c[0]+d;
    c[0]=3;
    c[1]=4;
    c[2]=5;
    c[13]=6;

    if(a == b){
        a = a + b;
    }
    while(a!=b){
        a = a + 1;
    }
    break;
    continue;
    return;
    return 3;
}
  
  `;

  // optionally: use local storage to save the code
  // and seek to restore any previous code from our last session
  if (window.localStorage) {
    const storedCode = window.localStorage.getItem("mainCode");
    if (storedCode !== null) {
      mainCode = storedCode;
    }
  }

  return mainCode;
}

function getWorker() {
  const workerURL = new URL("SysYPlus-server-worker.js", window.location.href);
  return new Worker(workerURL.href, {
    type: "module",
    name: "sysyplusLS",
  });
}
type WorkerUrl = string;

/**
 * Classic configuration for the monaco editor (for use with a Monarch grammar)
 */
interface ClassicConfig {
  code: string;
  htmlElement: HTMLElement;
  languageId: string;
  worker: WorkerUrl | Worker;
  monarchGrammar: any;
}

/**
 * Generates a valid UserConfig for a given Langium example
 *
 * @param config An extended or classic editor config to generate a UserConfig from
 * @returns A completed UserConfig
 */
function createUserConfig(config: ClassicConfig): UserConfig {
  // setup urls for config & grammar
  const id = config.languageId;

  // generate langium config
  return {
    htmlElement: config.htmlElement,
    wrapperConfig: {
      editorAppConfig: {
        $type: "classic",
        languageId: id,
        useDiffEditor: false,
        code: config.code,
        theme: "vs-dark",
        languageDef: config.monarchGrammar,
      },
      serviceConfig: {
        enableModelService: true,
        configureConfigurationService: {
          defaultWorkspaceUri: "/tmp/",
        },
        enableKeybindingsService: true,
        enableLanguagesService: true,
        debugLogging: false,
      },
    },
    languageClientConfig: {
      options: {
        $type: "WorkerDirect",
        worker: config.worker as Worker,
        name: `${id}-language-server-worker`,
      },
    },
  };
}

// create a wrapper instance
const wrapper = new MonacoEditorLanguageClientWrapper();

// start up with a user config
(async () => {
  // 保持setup调用在start之前
  setup();

  // 将await操作移入async函数作用域
  await wrapper.start(
    createUserConfig({
      htmlElement: document.getElementById("monaco-editor-root")!,
      languageId: "minilogo",
      code: getMainCode(),
      worker: getWorker(),
      monarchGrammar: getMonarchGrammar(),
    })
  );
})();
